package com.lulalei.dbviewer.commons.factory.GenerateCodeFactory;

import com.lulalei.dbviewer.commons.bean.GenerateBean;
import com.lulalei.dbviewer.commons.bean.TableBean;
import com.lulalei.dbviewer.commons.enums.LevelEnums;
import com.lulalei.dbviewer.commons.exception.CustomizeException;
import com.lulalei.dbviewer.commons.utils.NameCovertUtils;
import com.lulalei.dbviewer.commons.utils.ProjectPathUtils;
import com.lulalei.dbviewer.dto.GenerateClassDTO;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

@Component
public class VelocityGenerateFactory extends BasicGenerateCodeFactory {

    @Override
    public void generateAll(GenerateBean generateBean) throws CustomizeException {
        // 处理tableBean的name属性和rows中的name属性
        for (TableBean table : generateBean.getTables()) {
            String name = table.getName();
            //首字母大写
            name = NameCovertUtils.toBigHump(name);
            table.setName(name);
        }

        //生成实体类
        generateBean(generateBean);
        //生成dao
        generateDao(generateBean);
        //生成dao.xml
        generateXml(generateBean);
    }

    @Override
    public void generateBean(GenerateBean generateBean) throws CustomizeException {
        // 加载模板
        Template template = loadTemplate("template/Entity.vm");

        LevelEnums entity = LevelEnums.ENTITY;
        //按照集合生成文件
        generateAllFile(entity, template, generateBean.getTables(), generateBean.getJavaCodeDir(), generateBean.getModuleQualifiedName());
    }

    @Override
    public void generateDao(GenerateBean generateBean) throws CustomizeException {
        // 加载模板
        Template template = loadTemplate("template/Dao.vm");

        LevelEnums dao = LevelEnums.DAO;
        //按照集合生成文件
        generateAllFile(dao, template, generateBean.getTables(), generateBean.getJavaCodeDir(), generateBean.getModuleQualifiedName());
    }

    @Override
    public void generateXml(GenerateBean generateBean) throws CustomizeException {
        // 加载模板
        Template template = loadTemplate("template/DaoXml.vm");
        //选定需要生成哪一层级的文件
        LevelEnums daoXml = LevelEnums.DAO_XML;
        //按照集合生成文件
        generateAllFile(daoXml, template, generateBean.getTables(), generateBean.getXmlDir(), generateBean.getModuleQualifiedName());
    }

    /**
     * 按照给定模板生成集合中所有的表对应的文件
     */
    private void generateAllFile(LevelEnums levelEnums, Template template, List<TableBean> tableBeans, String basicPath, String moduleQualifiedName) throws CustomizeException {
        //遍历每一条表数据，为每一张表生成对应的java实体类
        for (TableBean table : tableBeans) {
            //构建数据
            GenerateClassDTO generateDTO = buildData(levelEnums, table, basicPath, moduleQualifiedName);

            //生成文件
            try {
                generateFile(generateDTO, template);
            } catch (IOException e) {
                e.printStackTrace();
                throw new CustomizeException(table.getName() + ".java文件生成失败");
            }
        }
    }

    /**
     * 构建生成文件时所需要的数据
     */
    private GenerateClassDTO buildData(LevelEnums levelEnums, TableBean tableBean, String basicPath, String moduleQualifiedName) {
        GenerateClassDTO generateDTO = new GenerateClassDTO();

        generateDTO.setLevel(levelEnums);

        generateDTO.setTableBean(tableBean);

        generateDTO.setModuleQualifiedName(moduleQualifiedName);
        String path = ProjectPathUtils.buildPath(basicPath + File.separator + levelEnums.getPath());
        generateDTO.setFilePath(path + File.separator + tableBean.getName() + levelEnums.getSuffix());

        return generateDTO;
    }

    /**
     * 按照给定模板生成单个文件
     */
    private void generateFile(GenerateClassDTO generateDTO, Template template) throws IOException {
        VelocityContext context = new VelocityContext();
        context.put("generate", generateDTO);

        //创建文件输出流
        FileWriter fileWriter = new FileWriter(generateDTO.getFilePath());

        // 生成文件
        template.merge(context, fileWriter);

        fileWriter.flush();
        fileWriter.close();
    }


    /**
     * 加载vm模板
     *
     * @param vmTemplatePath vm模板相对resource的路径
     * @return vm的Template类
     */
    private Template loadTemplate(String vmTemplatePath) {
        VelocityEngine velocityEngine = new VelocityEngine();
        Properties properties = new Properties();

        velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        velocityEngine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        velocityEngine.init(properties);

        return velocityEngine.getTemplate(vmTemplatePath, "utf-8");
    }
}
